import logging

from django.shortcuts import render

# Create your views here.
from fdfs_client.client import get_tracker_conf, Fdfs_client
from rest_framework.decorators import action
from rest_framework.mixins import CreateModelMixin
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR, \
    HTTP_403_FORBIDDEN
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from rest_framework.permissions import IsAuthenticated

from config.fastdfsConfig import FASTDFS_SERVER_DOMAIN
from de.settings import alipay
from utils.permission import wrap_permisssion, TeacherPermission, auto_user, update_auto_user, destroy_auto_user
from .serializers import *

# 导入日志器
logger = logging.getLogger(__name__)
# 创建FastDFS客户端对象
tracker_path = get_tracker_conf('utils/fastdfs/client.conf')  # 将fastdfs配置信息赋值给tracker_path
client = Fdfs_client(tracker_path)  # 创建客户端对象引入tracker_path内容用变量client接收


class ClassificationViewSet(ModelViewSet):
    queryset = Classification.objects.filter(is_delete=False, parent=None)
    serializer_class = ParentClassificationSerializer
    permission_classes = [IsAuthenticated]

    @wrap_permisssion(TeacherPermission)
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)

    @action(methods=['get'], detail=True)
    def commodity(self, request, pk):
        try:
            classification = Classification.objects.filter(is_delete=False).get(id=pk)  # 获取前端传入的数据pk对照model中的id 返回数据
        except Classification.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        classification_attr = 'classification1'
        classification_name = classification.name
        if classification.parent:
            classification_attr = 'classification2'  # 如parent为真，有数据则classification_attr = classification2
            classification_name = f'{classification.parent.name}--{classification.name}'  # 如果存在parentid则classification_name = 一级类目--二级类目
        data = getattr(classification, classification_attr).filter(is_delete=False, status=1)
        return Response({
            'classification': classification_name,
            'commodity': CommoditySerializer(data, many=True).data
        })


class CommodityViewSet(ModelViewSet):
    queryset = Commodity.objects.filter(is_delete=False)
    serializer_class = CommoditySerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        if self.action in ['list', 'retrieve']:
            return Commodity.objects.filter(is_delete=False, status=1)
        return self.queryset

    @wrap_permisssion(TeacherPermission)
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)

    @action(methods=['post'], detail=True)
    def img(self, request, pk):
        # 获取商品信息id,做异常处理
        try:
            commodity = self.get_queryset().get(id=pk)
        except Commodity.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        # 上传图片逻辑
        # 得到上传文件数据
        file = request.FILES.get('file')  # 获取前端传入的file字段的request保存到变量file
        # 判断是否有图片数据，文件类型是否是图片
        if not file or file.content_type not in ('image/jpeg', 'image/png', 'image/gif'):
            # 不是则返回客户端传入数据有误
            return Response(status=HTTP_400_BAD_REQUEST)
        # 是，前端传入的数据符合要求则交给FastDFS，存储到可用的storage服务上
        # 得到文件的后缀名，如果没有后缀名则默认为png
        try:
            images_ext_name = file.name.split('.')[-1]  # 将传入数据file以.分割，到-1index，也就是.到最后
        except Exception as e:
            logger.info('图片拓展名异常:%s' % e)  # 日志器info记录
            images_ext_name = 'png'  # 抛出异常后并把images_ext_name赋值png
        # 上传图片数据，通过字节流
        try:
            upload_res = client.upload_by_buffer(file.read(), file_ext_name=images_ext_name)
        except Exception as e:
            logger.error('图片上传异常：%s' % e)
            return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            if upload_res.get('Status') != 'Upload successed.':
                logger.warning('图片上传失败')
                return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
            # 得到返回的file_id
            image_name = upload_res.get('Remote file_id').decode()
            image_url = FASTDFS_SERVER_DOMAIN + image_name  # 图片地址是域名FASTDFS_SERVER_DOMAIN加名字
            # 保存图片地址到数据库
            CommodityImg.objects.create(src=image_url, commodity=commodity)
            # 返回
            return Response({'data': image_url})

    @action(methods=['get'], detail=False)
    def optimization(self, request):
        queryset = self.get_queryset().order_by('-comments').order_by('-sales')
        return Response(self.get_serializer(queryset[:5], many=True).data)


class ShoppingCartViewSet(ModelViewSet):
    serializer_class = ShoppingCartSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return self.request.user.shoppingcart_set.all()

    @auto_user
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @update_auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @destroy_auto_user
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)


class OrderViewSet(ReadOnlyModelViewSet, CreateModelMixin):
    serializer_class = OrderSerializer

    # permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return self.request.user.order_set.all()

    @action(methods=['put'], detail=False)
    def status(self, request):
        # 得到支付宝回调过来的数据，在请求地址里面
        query_dict = request.query_params  # 得到地址栏的参数
        data = query_dict.dict()

        # 不能无脑直接修改订单状态，核实身份
        try:
            sign = data.pop('sign')  # 类似token
        except KeyError:
            return Response(status=HTTP_400_BAD_REQUEST)

        # 验证sign
        res = alipay.verify(data, sign)
        if not res:
            return Response(status=HTTP_403_FORBIDDEN)

        # 得到订单号，支付宝交易号
        order_id = data.get('out_trade_no')  # 订单标号
        trade_no = data.get('trade_no')  # 支付宝交易号

        # 保存支付信息，修改订单状态
        with transaction.atomic():
            save_point = transaction.savepoint()
            try:
                Payment.objects.create(order_id=order_id, trade_id=trade_no)
                Order.objects.filter(order_id=order_id, status=1).update(status=2)
            except Exception as e:
                transaction.savepoint_rollback(save_point)
                raise serializers.ValidationError(e)
            else:
                transaction.savepoint_commit(save_point)
        return Response({'order_id': order_id, 'trade_id': trade_no})


class PaymentViewSet(ReadOnlyModelViewSet):
    queryset = Payment.objects.all()
    serializer_class = PaymentSerializer

    # permission_classes = [IsAuthenticated]

    @action(methods=['get'], detail=True)
    def pay(self, request, pk):
        # 获取订单信息，必须是当前登陆的用户的订单，并且是没有被支付的订单
        try:
            order = Order.objects.get(order_id=pk, user=request.user, status=1)
        except Order.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        # 通过支付宝对象处理订单信息
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order.order_id,  # 订单号
            total_amount=str(order.total_amount),  # 要支付的金额
            subject=f'PROMOTE{order.order_id}',  # 标题
            return_url='http://localhost:8002/home/order/success'
        )
        # 将订单信息发送给支付宝
        pay_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string

        # 返回支付宝页面
        return Response({'pay_url': pay_url})
import logging

from django.shortcuts import render

# Create your views here.
from fdfs_client.client import get_tracker_conf, Fdfs_client
from rest_framework.decorators import action
from rest_framework.mixins import CreateModelMixin
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR, \
    HTTP_403_FORBIDDEN
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from rest_framework.permissions import IsAuthenticated

from config.fastdfsConfig import FASTDFS_SERVER_DOMAIN
from de.settings import alipay
from utils.permission import wrap_permisssion, TeacherPermission, auto_user, update_auto_user, destroy_auto_user
from .serializers import *

# 导入日志器
logger = logging.getLogger(__name__)
# 创建FastDFS客户端对象
tracker_path = get_tracker_conf('utils/fastdfs/client.conf')  # 将fastdfs配置信息赋值给tracker_path
client = Fdfs_client(tracker_path)  # 创建客户端对象引入tracker_path内容用变量client接收


class ClassificationViewSet(ModelViewSet):
    queryset = Classification.objects.filter(is_delete=False, parent=None)
    serializer_class = ParentClassificationSerializer
    permission_classes = [IsAuthenticated]

    @wrap_permisssion(TeacherPermission)
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)

    @action(methods=['get'], detail=True)
    def commodity(self, request, pk):
        try:
            classification = Classification.objects.filter(is_delete=False).get(id=pk)  # 获取前端传入的数据pk对照model中的id 返回数据
        except Classification.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        classification_attr = 'classification1'
        classification_name = classification.name
        if classification.parent:
            classification_attr = 'classification2'  # 如parent为真，有数据则classification_attr = classification2
            classification_name = f'{classification.parent.name}--{classification.name}'  # 如果存在parentid则classification_name = 一级类目--二级类目
        data = getattr(classification, classification_attr).filter(is_delete=False, status=1)
        return Response({
            'classification': classification_name,
            'commodity': CommoditySerializer(data, many=True).data
        })


class CommodityViewSet(ModelViewSet):
    queryset = Commodity.objects.filter(is_delete=False)
    serializer_class = CommoditySerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        if self.action in ['list', 'retrieve']:
            return Commodity.objects.filter(is_delete=False, status=1)
        return self.queryset

    @wrap_permisssion(TeacherPermission)
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)

    @action(methods=['post'], detail=True)
    def img(self, request, pk):
        # 获取商品信息id,做异常处理
        try:
            commodity = self.get_queryset().get(id=pk)
        except Commodity.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        # 上传图片逻辑
        # 得到上传文件数据
        file = request.FILES.get('file')  # 获取前端传入的file字段的request保存到变量file
        # 判断是否有图片数据，文件类型是否是图片
        if not file or file.content_type not in ('image/jpeg', 'image/png', 'image/gif'):
            # 不是则返回客户端传入数据有误
            return Response(status=HTTP_400_BAD_REQUEST)
        # 是，前端传入的数据符合要求则交给FastDFS，存储到可用的storage服务上
        # 得到文件的后缀名，如果没有后缀名则默认为png
        try:
            images_ext_name = file.name.split('.')[-1]  # 将传入数据file以.分割，到-1index，也就是.到最后
        except Exception as e:
            logger.info('图片拓展名异常:%s' % e)  # 日志器info记录
            images_ext_name = 'png'  # 抛出异常后并把images_ext_name赋值png
        # 上传图片数据，通过字节流
        try:
            upload_res = client.upload_by_buffer(file.read(), file_ext_name=images_ext_name)
        except Exception as e:
            logger.error('图片上传异常：%s' % e)
            return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            if upload_res.get('Status') != 'Upload successed.':
                logger.warning('图片上传失败')
                return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
            # 得到返回的file_id
            image_name = upload_res.get('Remote file_id').decode()
            image_url = FASTDFS_SERVER_DOMAIN + image_name  # 图片地址是域名FASTDFS_SERVER_DOMAIN加名字
            # 保存图片地址到数据库
            CommodityImg.objects.create(src=image_url, commodity=commodity)
            # 返回
            return Response({'data': image_url})

    @action(methods=['get'], detail=False)
    def optimization(self, request):
        queryset = self.get_queryset().order_by('-comments').order_by('-sales')
        return Response(self.get_serializer(queryset[:5], many=True).data)


class ShoppingCartViewSet(ModelViewSet):
    serializer_class = ShoppingCartSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return self.request.user.shoppingcart_set.all()

    @auto_user
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    @update_auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    @destroy_auto_user
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)


class OrderViewSet(ReadOnlyModelViewSet, CreateModelMixin):
    serializer_class = OrderSerializer

    # permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return self.request.user.order_set.all()

    @action(methods=['put'], detail=False)
    def status(self, request):
        # 得到支付宝回调过来的数据，在请求地址里面
        query_dict = request.query_params  # 得到地址栏的参数
        data = query_dict.dict()

        # 不能无脑直接修改订单状态，核实身份
        try:
            sign = data.pop('sign')  # 类似token
        except KeyError:
            return Response(status=HTTP_400_BAD_REQUEST)

        # 验证sign
        res = alipay.verify(data, sign)
        if not res:
            return Response(status=HTTP_403_FORBIDDEN)

        # 得到订单号，支付宝交易号
        order_id = data.get('out_trade_no')  # 订单标号
        trade_no = data.get('trade_no')  # 支付宝交易号

        # 保存支付信息，修改订单状态
        with transaction.atomic():
            save_point = transaction.savepoint()
            try:
                Payment.objects.create(order_id=order_id, trade_id=trade_no)
                Order.objects.filter(order_id=order_id, status=1).update(status=2)
            except Exception as e:
                transaction.savepoint_rollback(save_point)
                raise serializers.ValidationError(e)
            else:
                transaction.savepoint_commit(save_point)
        return Response({'order_id': order_id, 'trade_id': trade_no})


class PaymentViewSet(ReadOnlyModelViewSet):
    queryset = Payment.objects.all()
    serializer_class = PaymentSerializer

    # permission_classes = [IsAuthenticated]

    @action(methods=['get'], detail=True)
    def pay(self, request, pk):
        # 获取订单信息，必须是当前登陆的用户的订单，并且是没有被支付的订单
        try:
            order = Order.objects.get(order_id=pk, user=request.user, status=1)
        except Order.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        # 通过支付宝对象处理订单信息
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order.order_id,  # 订单号
            total_amount=str(order.total_amount),  # 要支付的金额
            subject=f'PROMOTE{order.order_id}',  # 标题
            return_url='http://localhost:8080/home/order/success'
        )
        # 将订单信息发送给支付宝
        pay_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string

        # 返回支付宝页面
        return Response({'pay_url': pay_url})
